(* Program 1.1 *)

use "ast.sml";

(* maxargs -- largest number of arguments to a PrintStm *)
val maxargs : stm -> int =
    let fun maxargsStm (CompoundStm (s, s')) = Int.max (maxargsStm s, maxargsStm s')
	  | maxargsStm (AssignStm (_, e)) = maxargsExp e
	  | maxargsStm (PrintStm es) = Int.max (List.length es, maxargsList es)
				       
	and maxargsExp (IdExp _) = 0
	  | maxargsExp (NumExp _) = 0
	  | maxargsExp (OpExp (e, _, e')) = Int.max (maxargsExp e, maxargsExp e')
	  | maxargsExp (EseqExp (s, e)) = Int.max (maxargsStm s, maxargsExp e)
					  
	and maxargsList [] = 0
	  | maxargsList (e::es) = Int.max (maxargsExp e, maxargsList es);
    in maxargsStm
    end

(* testing *)
val exp3 = NumExp 3;
val exp4 = NumExp 4;
val expI = IdExp "i";
val expJ = IdExp "j";
val exp7 = OpExp(exp3, Plus, exp4);
val expI3 = OpExp(expI, Plus, exp3);

val prog1  = AssignStm ("i", exp3);
val prog2  = AssignStm ("j", expI);
val prog3  = AssignStm ("j", exp7);
val prog4  = CompoundStm (prog1, prog2);
val prog5  = AssignStm ("j", expI3);
val prog6  = CompoundStm (prog4, prog5);
val prog7  = PrintStm [];
val prog8  = PrintStm [exp3];
val prog9  = PrintStm [exp3, exp4];
val prog10 = PrintStm [exp3, exp4, exp7];
val prog11 = PrintStm [EseqExp (prog6, expI3), expI];
val prog12 = PrintStm [EseqExp (prog6, EseqExp (prog7, expJ)), expJ];
val prog13 = PrintStm [EseqExp (prog11, EseqExp (prog10, expI))];
val prog14 = PrintStm [EseqExp (prog13, expI), expI3, EseqExp (prog10, expJ), exp3];

use "assert.sml";

assert (0 = maxargs(prog1),  "1");
assert (0 = maxargs(prog2),  "2");
assert (0 = maxargs(prog3),  "3");
assert (0 = maxargs(prog4),  "4");
assert (0 = maxargs(prog5),  "5");
assert (0 = maxargs(prog6),  "6");
assert (0 = maxargs(prog7),  "7");
assert (1 = maxargs(prog8),  "8");
assert (2 = maxargs(prog9),  "9");
assert (3 = maxargs(prog10), "10");
assert (2 = maxargs(prog11), "11");
assert (2 = maxargs(prog12), "12");
assert (3 = maxargs(prog13), "13");
assert (4 = maxargs(prog14), "14");

OS.Process.exit OS.Process.success;
